
#include <stdio.h>
#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>


// 宏控制变量来对整数的某几个bit位置1或者清0


#define SET_BIT(X,N) (X = X | (1 << (N-1)))

#define CLEAR_BIT(X,N) (X = X & (~(1 << (N-1))))
/* 64为系统下指针的大小为8个字节,32位系统下为4个字节
 * 结构体的对齐依赖于系统的位数,%d:32 %ld:64
*/


typedef struct SMART_t
{
    int id;
    int num;
    char *p;
    char ki;

}SMART;

// 大小端定义,保持version在前，ihl在后
// Linux内核中的定义
// char * 取int数据是取低地址的
struct iphdr
{
    #if defined(__LITTLE_ENDIAN_BITFIELD) // 低字节存储到低地址
        uint8_t ihl:4,
                version:4;
    #elif defined(__BIG_ENDIAN_BITFIELD) // 高字节存储到低地址
        uint8_t version:4,
                ihl:4;
    #endif
};



// 有符号型整数，0 正 1 负
// 有符号数的取值范围是[-2^(w-1) , 2^(w-1)-1 ],因此1个bit 的范围是：-1 ~ 0
// 无符号数的取值范围是[0 , 2^w-1]

typedef struct vs_node
{
    long long freq_khz;// 8 bytes
    char skip_status:1; // 1 bytes中使用1bit来存放该变量  -1或者0
    char lock_status:1; // 1 bytes
    char work_status:6; // 1 bytes中使用6bit来存放该变量 -32 ~ 31
    char bug[3]; // 3 bytes
    char *ptr[8]; // 32位系统:32 bytes  64位系统:64 bytes
}vs_node_s; // 32位系统:48 bytes 64位系统: 80 bytes

// 函数指针类型的定义
typedef int (*func)(struct SMART *); 

int init_stu(SMART *stu)
{
    char str[] = "Hello World!";
    stu->id = 1;
    stu->num = 12;
    stu->p = str;
    stu->ki = 'c';


    return strlen(stu->p);
}

int add(int a, int b)
{
    return (a+b);
}



int main(int argc, char *argv[])
{
    // 函数指针，形参为结构体
    {
        SMART stu1;
        func test1 = init_stu;
        int str_len = test1(&stu1);
        printf("strlen: %ld \n",str_len);
    }

    // 简单的两数相加的函数指针的使用方法
    {
        int (*func1)(int ,int);

        func1 = add;

        printf("2+3 = %ld \n ",func1(2,3));

    }
    
    // 指针数组和数组指针的使用
    // 指针数组的核心是一个数组，数组中存储的是指针，由于优先级 () [] > *
    // 数组指针的核心是一个指针，指针指向该数组
    {
        // 指针数组 int *p[n] = {p1 ,p2,p3...}; p1 p2 p3 为指针
        char *p1; // 64位系统中的一个指针占8个字节
        int a = 1;
        int b = 2;
        int c = 3;

        int *pp[3];
        
        pp[0] = &a;
        pp[1] = &b;
        pp[2] = &c;

        for (int i = 0;i < 3;i++)
        {
            printf("pp[%d] = %p \n",i,pp[i]);
        }

        printf("Size: %ld P1: %ld \n",sizeof(SMART),sizeof(p1));



        // 数组指针,指向的是数组所在的内存空间
        // int array[5] array指数组名和数组首元素的地址，指针进行步长加减时，是一个元素；&array指的是数组的首地址，指针进行步长加减时，是整个数组
        // 指向数组和指向数组首元素的地址是两码事

        /*  int (*p)[n] = {n1,n2,n3...}; n1 n2 n3 为整数
         * （）与[ ] 优先级相同，根据结合律，就从左向右运算。
         * （）里是*p，先定义了指针，所以p是个指针，然后后面是[ ],才是数组，即数组指针。
         *  p是指针称为数组指针，指向含有n个int类型的元素的数组
        */

        int (*p2) [5];

        int array[5];

        for (int i = 0;i < 5;i++)
        {
            array[i] = i +1;
        }

        p2 = &array;

        // 地址一样表示的意思不一样，array表示数组和数组的首元素的地址，&array表示整个数组的地址
        // array+1表示对数组中的元素移动1位 &array+1表示对整个数组移动数组大小的地址
        printf("array addr: %p &array addr: %p \n",array,&array);

        printf("array addr1: %p &array addr1: %p \n",array+1,&array+1);

        printf("ss: %p \n",*p2);

        for (int i = 0;i < 5;i++)
        {
            //这里不能使用*(p2+1)来取其元素的值，因此p2是指向其数组地址的，不是数组首元素的地址,p2+1代表加了数组长度的地址
            // *p2+i代表它在数组中的位置,那么*(*p2+i)就代表取数组中对应下表元素的值
            // printf("p2[%d] = % d \n",i,*(*p2+i));
            printf("p2[%d] = % d \n",i,(*p2)[i]);
        }
        


    }

    {
        // 一个有10个指针的数组，该指针指向一个函数，该函数有一个整型参数并返回一个整型数，该怎么写呢
        int (*p4[10])(int);
    }


    // set bit and clear bit
    // 设置某一个数X的bitn为1  X |= (1 << (n-1))
    // 清理某一个数X的bitn为0  X |= (~(1 << (n-1)))
    {
        int a = 3;
        SET_BIT(a,3);
        SET_BIT(a,4);

        printf("a = %d \n",a);

        CLEAR_BIT(a,3);
        CLEAR_BIT(a,4);

        printf("a = %d \n",a);
    }

    // big endian and little endian 定义
    {
        typedef struct iphdr_t {
            uint8_t ihl:4,
                    version:4;
        }iphdr;

        iphdr iph_test;
        iph_test.ihl = 14; // [0,15]
        iph_test.version = 15; // [0,15]
        printf("iph size: %d ihl: %d version: %d \n",sizeof(iphdr),iph_test.ihl,iph_test.version);
    }
    {
        typedef struct version_t
        {
            uint8_t hu:4,
                    hu1:4;

        }version;
    }
    

    vs_node_s v_node_test;
    v_node_test.skip_status = 0; //111
    v_node_test.work_status = -32;

    printf("Test: %d %d \n",v_node_test.skip_status,v_node_test.work_status);

    printf("vs_node_s: %ld \n",sizeof(vs_node_s));

}